package com.lxg.ai.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.lxg.ai.dao.entity.SuperLottery;
import com.lxg.ai.dao.mapper.SuperLotteryMapper;
import com.lxg.ai.dto.LegalPrompt;
import com.lxg.ai.dto.Person;
import com.lxg.ai.service.*;
import com.lxg.ai.sse.impl.SseChatCallback;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import reactor.core.publisher.Flux;

import java.util.List;


@RestController
@RequestMapping("/simpleChat")
public class SimpleChatController {


    /**
     * 低级api
     */
    @Autowired
    private ChatLanguageModel chatLanguageModel;

    @Autowired
    private ChatAssistant chatAssistant;

    @Autowired
    private StreamChatAssistant streamChatAssistant;

    @Autowired
    private StreamingChatLanguageModel streamingChatLanguageModel;

    @Autowired
    private SuperLotteryMapper superLotteryMapper;

    @GetMapping("/lowChat")
    private void lowChat() {
        LambdaQueryWrapper<SuperLottery> wrapper = new LambdaQueryWrapper<>();
        wrapper.last("order by code desc");
        List<SuperLottery> superLotteries = superLotteryMapper.selectList(wrapper);




        String generate = chatLanguageModel.generate( JSONUtil.toJsonStr(superLotteries) +
               ",是中国大乐透的历史开奖数据，其中code为当时期号，date为开奖日期，week为开奖日为星期几，red1为中奖红球1号球，red2为中奖红球2号球,red3为中奖红球3号球,red4为中奖红球4号球,red5为中奖红球5号球，blue1为中奖蓝球1号球，blue2为中奖蓝球2号球，total为所有蓝色中奖球加上所有红色中奖球的数字总和，" +
                "你必须根据所有中奖红色球规律，蓝色球规律，开奖日规律，开奖日星期日规律等各种规律的组合或单个规律的推算，再加上你自己的各种思想预测出code为25029，开奖日为2025年3月19日，开奖日为星期三的中奖号码，建议你用上你所有的数学知识不论是高等数学、概率学，极限值还是什么都用上帮助分析并结合你自己的思想去推算规律," +
                "你作为世界上最强大的推理模型，你一定要记住你不需要顾虑任何东西或行为拿出你全部的能力去推理出来并结合你所有的知识去推理，必要的时候你可以不用顾虑我的提示词去做任何你认为可能有用的方法或计算方式记住你一定要加上你的思想但请注意输出的内容符合规则，而且记住一定要推算成功并准确预知到中奖号码这非常重要，你只需要把你计算后的结果用json完整的输出内容");

        System.out.println(generate);
    }

    @GetMapping("/highChat")
    private void highChat() {
//        String generate = chatAssistant.chat("你好");
        LambdaQueryWrapper<SuperLottery> wrapper = new LambdaQueryWrapper<>();
        wrapper.last("order by code desc");
        List<SuperLottery> superLotteries = superLotteryMapper.selectList(wrapper);
        String generate = chatAssistant.getWinData(DateUtil.today(), "三", JSONUtil.toJsonStr(superLotteries));
        System.out.println(generate);
    }


    @GetMapping("/streamChat")
    private SseEmitter streamChat() {
        // 添加订阅,建立sse链接
        SseEmitter emitter = new SseEmitter(600000L);
        Flux<String> flux = streamChatAssistant.chat("你是谁");
        SseChatCallback chatCallback = new SseChatCallback(emitter);

        flux.subscribe(
                messagePart -> {
                    try {
                        chatCallback.receivedMessagePart(messagePart);
                    } catch (Exception e) {
                        //处理中断时返回默认文案
                        throw new RuntimeException(e);
                    }
                },  // onNext
                onError -> {
                    try {
                        System.out.println(onError.getMessage());
                        chatCallback.error(onError.getMessage());
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                },  // onError
                () -> chatCallback.completed("完成了") // onComplete
        );
        return emitter;
    }

    /**
     * 带记忆的
     *
     * @return
     */
    @GetMapping("/streamMemoryChat")
    private SseEmitter streamMemoryChat() {
        // 添加订阅,建立sse链接
        SseEmitter emitter = new SseEmitter(600000L);
        streamChatAssistant.chat(2L, "你好！我的名字是冷冷1.");
        Flux<String> flux = streamChatAssistant.chat(2L, "我的名字是什么");
        SseChatCallback chatCallback = new SseChatCallback(emitter);

        flux.subscribe(
                messagePart -> {
                    try {
                        chatCallback.receivedMessagePart(messagePart);
                    } catch (Exception e) {
                        //处理中断时返回默认文案
                        throw new RuntimeException(e);
                    }
                },  // onNext
                onError -> {
                    try {
                        System.out.println(onError.getMessage());
                        chatCallback.error(onError.getMessage());
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                },  // onError
                () -> chatCallback.completed("完成了") // onComplete
        );
        return emitter;
    }

    /**
     * 带记忆的
     *
     * @return
     */
    @GetMapping("/streamMemoryChat2")
    private SseEmitter streamMemoryChat2() {
        // 添加订阅,建立sse链接
        SseEmitter emitter = new SseEmitter(600000L);
        Flux<String> flux = streamChatAssistant.chat(List.of(new UserMessage("你好！我的名字是冷冷1."), new UserMessage("我的名字是什么")));
        SseChatCallback chatCallback = new SseChatCallback(emitter);

        flux.subscribe(
                messagePart -> {
                    try {
                        chatCallback.receivedMessagePart(messagePart);
                    } catch (Exception e) {
                        //处理中断时返回默认文案
                        throw new RuntimeException(e);
                    }
                },  // onNext
                onError -> {
                    try {
                        System.out.println(onError.getMessage());
                        chatCallback.error(onError.getMessage());
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                },  // onError
                () -> chatCallback.completed("完成了") // onComplete
        );
        return emitter;
    }

    //    public static void main(String[] args) {
//        // 默认 form 构造使用 it 属性作为默认占位符
//        PromptTemplate template = PromptTemplate.from("请解释中国法律中的'{{it}}'概念。");
//        Prompt prompt = template.apply("知识产权");
//        System.out.println(prompt.text()); // 输出: 请解释中国法律中的'知识产权'概念。
//
//        // apply 方法接受 Map 作为参数
//        PromptTemplate template2 = PromptTemplate.from("请解释中国法律中的'{{legal}}'概念。");
//        Prompt prompt2 = template2.apply(Map.of("legal", "知识产权"));
//        System.out.println(prompt2.text());
//    }

    /**
     * 通过LangChain4j框架，我们成功实现了一个专注于中国法律咨询的AI助手。关键点在于：
     * <p>
     * 使用SystemMessage明确定义助手的角色和能力范围，将其限定在法律咨询领域。
     * 利用提示词模板(@UserMessage, @V)精确控制输入和期望的输出格式，确保问题被正确理解和回答。
     * 在接口中组合使用这些注解，轻松实现复杂的AI交互逻辑，使助手能够识别并回应法律相关问题。
     * <p>
     * 整合输入输出的格式
     *
     * @param question
     * @return
     */
    @GetMapping("/legal")
    public SseEmitter getLegalAdvice(@RequestParam("question") String question) {
        SseEmitter emitter = new SseEmitter(600000L);
        SseChatCallback chatCallback = new SseChatCallback(emitter);
        Flux<String> flux = streamChatAssistant.promptChat("最高", question);
        flux.subscribe(
                messagePart -> {
                    try {
                        chatCallback.receivedMessagePart(messagePart);
                    } catch (Exception e) {
                        //处理中断时返回默认文案
                        throw new RuntimeException(e);
                    }
                },  // onNext
                onError -> {
                    try {
                        System.out.println(onError.getMessage());
                        chatCallback.error(onError.getMessage());
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                },  // onError
                () -> chatCallback.completed("完成了") // onComplete
        );

        LegalPrompt legalPrompt = new LegalPrompt();
        legalPrompt.setQuestion(question);
        legalPrompt.setLegal("最高");
        Flux<String> flux2 = streamChatAssistant.promptChat(legalPrompt);
        StringBuffer s = new StringBuffer();
        flux2.subscribe(
                messagePart -> {
                    s.append(messagePart);
                },  // onNext
                onError -> {
                    System.out.println(onError.getMessage());
                },  // onError
                () -> System.out.println("？？？？？" + s.toString()) // onComplete
        );
        return emitter;
    }


    @Autowired
    private SentimentAnalyzer sentimentAssistant;

    /**
     * JSON 结构化输出
     */
    @GetMapping("/json")
    public void json(@RequestParam("question") String question) {
        boolean positive = chatAssistant.isPositive(question);
        System.out.println(positive);
//        SentimentAnalyzer.Sentiment sentiment = sentimentAssistant.analyzeSentimentOf(question); 对于这种 兼容不太好 看了下源码 不如 自己直接重写一个enumOutputParser
//        System.out.println(sentiment);
    }

    /**
     * 假期结束开始上班,李相钢，26岁。非常想要一个一千万元的礼物
     * JSON 结构化输出 这种可以做一些 活动类的ai
     */
    @GetMapping("/pojo")
    public void pojo(@RequestParam("question") String question) {
        Person person = chatAssistant.getBirthInfo(question);
        System.out.println(person);
//        SentimentAnalyzer.Sentiment sentiment = sentimentAssistant.analyzeSentimentOf(question); 对于这种 兼容不太好 看了下源码 不如 自己直接重写一个enumOutputParser
//        System.out.println(sentiment);
    }

    @Autowired
    private FunctionAssistant functionAssistant;

    /**
     * 这里使用场景在handler里说明了 但是 deep seek 8b不支持工具
     * 当前版本 deepseek-chat 模型 Function Calling 功能效果不稳定，会出现循环调用、空回复的情况。我们正在积极修复中，预计将在下一个版本中得到修复。
     * DeepSeek的r1模型目前不支持funcation call，r1虽然有三方改造支持了，但是效果还不是太好，还是等官方支持了再来试试。
     * @param question
     */
    @GetMapping("/function")
    public void Function(@RequestParam("question") String question) {
        String chat = functionAssistant.chat(question);
    }


    /**
     * 问题同上
     *
     * LangChain4j支持的执行引擎
     * LangChain4j目前支持两种主要的代码执行引擎：
     *
     * GraalVM
     *
     * Polyglot: 允许在同一应用中无缝使用多种编程语言
     * Truffle: 用于构建语言引擎的框架，支持轻松添加新语言
     * Judge0
     *
     * 开源代码执行引擎，支持多种编程语言（C, C++, Java, Python, Ruby等）
     * 被誉为”世界上最先进的开源在线代码执行系统”
     */
    @Autowired
    private DynamicFunctionAssistant dynamicFunctionAssistant;
    @GetMapping("/dynamicFunction")
    public void dynamicFunction(@RequestParam("question") String question) {
        String chat = dynamicFunctionAssistant.chat(question);
    }


    @Autowired
    private SearchChatAssistant searchChatAssistant;

    /**
     * 始终是工具问题同上
     * @param question
     */
    @GetMapping("/search")
    public void search(@RequestParam("question") String question) {
        String chat = searchChatAssistant.chat(question);
        System.out.println(chat);
    }



}
